using System.Collections.Generic;
using System.Reflection;
using System.Text;
using Unity.Entities;
using UnityEditor;
using UnityEngine;
using UnityEngine.UIElements;

namespace EntitiesView.Editor
{
    public class EntityViewConfigEditor : EditorWindow
    {
        UnityEditor.Editor editor;

        public void CreateGUI()
        {
            editor = UnityEditor.Editor.CreateEditor(EntityViewerConfig.Instance);
        }

        [MenuItem("Tools/EntityView/Config")]
        public static void ShowExample()
        {
            EntityViewConfigEditor wnd = GetWindow<EntityViewConfigEditor>();
            wnd.titleContent = new GUIContent("EntityViewerConfig");
        }

        private void OnGUI()
        {
            editor.OnInspectorGUI();
            if (GUILayout.Button("Generate Script"))
            {
                GenerateCSharp();
            }

            if (GUILayout.Button("Clean Script"))
            {
                GenerateCSharpEmpty();
            }
        }

        void GenerateCSharp()
        {
            EntityDataProcessGenerater entityDataProcessGenerate = new EntityDataProcessGenerater
            {
                buffElementTypes = EntityViewerConfig.IBuffElementTypes(),
                componentDataTypes = EntityViewerConfig.ComponentDataTypes()
            };
            entityDataProcessGenerate.Generate(EntityViewerConfig.Path);
            AssetDatabase.Refresh();
        }

        void GenerateCSharpEmpty()
        {
            EntityDataProcessGenerater entityDataProcessGenerate = new EntityDataProcessGenerater();
            entityDataProcessGenerate.GenerateEmpty(EntityViewerConfig.Path);
            AssetDatabase.Refresh();
        }
    }

    public class EntityViewer : EditorWindow
    {
        public class MyTextField : TextField
        {
            public MyTextField(string label) : base(label)
            {
            }

            public void SetText(string msg)
            {
                text = msg;
            }
        }

        [SerializeField] private VisualTreeAsset m_VisualTreeAsset = default;

        [MenuItem("Tools/EntityView/Viewer")]
        public static void ShowExample()
        {
            EntityViewer wnd = GetWindow<EntityViewer>();
            wnd.titleContent = new GUIContent("EntityViewer");
        }

        private Button refreshBtn;
        private MyTextField textField;
        private Label contentLabel;
        private ScrollView scrollView;
        private ListView listView;

        public void CreateGUI()
        {
            // Each editor window contains a root VisualElement object
            VisualElement root = rootVisualElement;

            textField = new MyTextField("Path");
            textField.SetText(EntityViewerConfig.Path);

            refreshBtn = new Button()
            {
                text = "刷新",
                clickable = new Clickable(SearchEntities)
            };

            // Instantiate UXML
            VisualElement labelFromUXML = m_VisualTreeAsset.Instantiate();
            root.Add(labelFromUXML);
            root.Add(textField);
            root.Add(refreshBtn);

            scrollView = root.Q<ScrollView>("content");
            contentLabel = new Label();
            scrollView.Add(contentLabel);
            listView = root.Q<ListView>("list");
            listView.selectionChanged -= OnListSelectionChange;
            SearchEntities();
            EditorApplication.playModeStateChanged += mode =>
            {
                if (mode == PlayModeStateChange.ExitingPlayMode || mode == PlayModeStateChange.EnteredPlayMode)
                {
                    Debug.Log("PlayModeStateChanged");
                    SearchEntities();
                }
            };
        }

        void SearchEntities()
        {
            hasEntity = false;
           
            if (World.DefaultGameObjectInjectionWorld != null)
            {
                List<string> items = new List<string>();
                List<EntityEdit> itemsE = new List<EntityEdit>();
                EntityManager entityMgr = World.DefaultGameObjectInjectionWorld.EntityManager;
                var entities = entityMgr.GetAllEntities();
                for (int i = 0; i < entities.Length; ++i)
                {
                    var item = entities[i];
                    itemsE.Add(new EntityEdit()
                    {
                        Index = item.Index,
                        Version = item.Version,
                        Name = $"{entityMgr.GetName(item)}({item.Index}:{item.Version})"
                    });
                }

                entities.Dispose();
                listView.itemsSource = itemsE;
                listView.selectionChanged += OnListSelectionChange;
            }
        }

        Entity currSelectEntity;
        bool hasEntity = false;

        private void OnListSelectionChange(IEnumerable<object> obj)
        {
            EntityManager entityMgr = World.DefaultGameObjectInjectionWorld.EntityManager;
            StringBuilder stringBuilder = new StringBuilder();
            foreach (EntityEdit item in obj)
            {
                Entity entity = new Entity() { Index = item.Index, Version = item.Version };
                currSelectEntity = entity;
                hasEntity = true;
                GetEntityAllData(entity, stringBuilder);
            }

            contentLabel.text = stringBuilder.ToString();
        }

        void GetEntityAllData(Entity entity, StringBuilder stringBuilder)
        {
            Assembly editorAssembly = Assembly.Load("Assembly-CSharp-Editor");
            var typeClass = editorAssembly.GetType("EntitiesViewer.Editor.EntityDataProcess");

            var buffElementDataToStringMethod = typeClass.GetMethod("IBuffElementDataToString");
            var componentDataToStringMethod = typeClass.GetMethod("ComponentDataToString");

            EntityManager entityMgr = World.DefaultGameObjectInjectionWorld.EntityManager;
            var types = entityMgr.GetComponentTypes(entity);
            for (int i = 0; i < types.Length; ++i)
            {
                ComponentType type = types[i];
                if (type.IsBuffer)
                {
                    var tempName = type.ToString().Replace(" [Buffer]", "");
                    var res = (string)buffElementDataToStringMethod.Invoke(null, new object[] { tempName, entity });
                    // var res = EntityDataProcess.IBuffElementDataToString(tempName, entity);
                    if (string.IsNullOrEmpty(res))
                    {
                        stringBuilder.AppendLine(tempName);
                    }
                    else
                    {
                        stringBuilder.AppendLine(res);
                    }
                }
                else if (type.IsSharedComponent)
                {
                    // 处理ISharedComponentData类型的组件
                    // 示例：SomeSharedComponentData sharedComponent = entityManager.GetSharedComponentData<SomeSharedComponentData>(entity);
                    stringBuilder.AppendLine(type.ToString() + "\n");
                }
                else
                {
                    var tempName = type.ToString();
                    var res = (string)componentDataToStringMethod.Invoke(null, new object[] { tempName, entity });
                    //var res = EntityDataProcess.ComponentDataToString(tempName, entity);
                    if (string.IsNullOrEmpty(res))
                    {
                        stringBuilder.AppendLine(tempName);
                    }
                    else
                    {
                        stringBuilder.AppendLine(res);
                    }
                }
            }

            types.Dispose();
        }

        private void OnInspectorUpdate()
        {
            if (hasEntity)
            {
                EntityManager entityMgr = World.DefaultGameObjectInjectionWorld.EntityManager;
                StringBuilder stringBuilder = new StringBuilder();
                GetEntityAllData(currSelectEntity, stringBuilder);
                contentLabel.text = stringBuilder.ToString();
            }
            else
            {
                contentLabel.text = "Has Not Select Entity";
            }
        }

        static void GenerateCSharp()
        {
            EntityDataProcessGenerater entityDataProcessGenerater = new EntityDataProcessGenerater();
            entityDataProcessGenerater.buffElementTypes = EntityViewerConfig.IBuffElementTypes();
            entityDataProcessGenerater.componentDataTypes = EntityViewerConfig.ComponentDataTypes();
            entityDataProcessGenerater.Generate(EntityViewerConfig.Path);
            AssetDatabase.Refresh();
        }

        static void GenerateCleanCSharp()
        {
            EntityDataProcessGenerater entityDataProcessGenerater = new EntityDataProcessGenerater();
            entityDataProcessGenerater.buffElementTypes = EntityViewerConfig.IBuffElementTypes();
            entityDataProcessGenerater.componentDataTypes = EntityViewerConfig.ComponentDataTypes();
            entityDataProcessGenerater.GenerateEmpty(EntityViewerConfig.Path);
            AssetDatabase.Refresh();
        }

        [MenuItem("Tools/EntityView/Generate Script", priority = 1)]
        static void Generate()
        {
            GenerateCSharp();
        }

        [MenuItem("Tools/EntityView/Clean Script", priority = 0)]
        static void Clean()
        {
            GenerateCleanCSharp();
        }

        public struct EntityEdit
        {
            public int Index;
            public int Version;
            public string Name;

            public override string ToString()
            {
                return Name;
            }
        }
    }
}

